Appearance
大纲
- RabbitMQ是什么
- RabbitMQ的组成部分
- RabbitMQ 的工作流程
- RabbitMQ广播和直接模式示例
一、基础概念
“消息队列(Message Queue)”是在消息的传输过程中保存消息的容器。
MQ 的核心作用:削峰、解耦、异步
RabbitMQ是什么
建议直接去官网看一下相关概念: https://www.rabbitmq.com/documentation.html
RabbitMQ的特点
RabbitMQ是一款使用Erlang语言开发的,实现AMQP(高级消息队列协议)的开源消息中间件。
特点
- 可靠性。支持持久化,传输确认,发布确认等保证了MQ的可靠性。
- 灵活的分发消息策略。这应该是RabbitMQ的一大特点。在消息进入MQ前由Exchange(交换机)进行路由消息。分发消息策略有:简单模式、工作队列模式、发布订阅模式、路由模式、通配符模式。
- 支持集群。多台RabbitMQ服务器可以组成一个集群,形成一个逻辑Broker。
- 多种协议。RabbitMQ支持多种消息队列协议,比如 STOMP、MQTT 等等。
- 支持多种语言客户端。RabbitMQ几乎支持所有常用编程语言,包括 Java、.NET、Ruby 等等。
- 可视化管理界面。RabbitMQ提供了一个易用的用户界面,使得用户可以监控和管理消息 Broker。
- 插件机制。RabbitMQ提供了许多插件,可以通过插件进行扩展,也可以编写自己的插件。
安装和使用
- 安装 erlang 环境
- 安装RabbitMQ服务端
RabbitMQ的组成部分
核心概念
- Broker:消息队列服务进程。此进程包括两个部分:Exchange和Queue。
- Exchange:消息队列交换机。按一定的规则将消息路由转发到某个队列。
- Queue:消息队列,存储消息的队列。
- Producer:消息生产者。生产方客户端将消息同交换机路由发送到队列中。
- Consumer:消息消费者。消费队列中存储的消息。
大概流程:

- 消息生产者连接到RabbitMQ Broker,创建connection,开启channel。
- 生产者声明交换机类型、名称、是否持久化等。
- 生产者发送消息,并指定消息是否持久化等属性和 routing key。
- exchange收到消息之后,根据routing key路由到跟当前交换机绑定的相匹配的队列里面。
- 消费者监听接收到消息之后开始业务处理
生产者 --[消息]--> 交换机 --[路由]--> 队列 --[消费]--> 消费者
\ /
\--[通道 Channel]-----------------------/通道的概念:
- 定义:通道是建立在实际的 TCP 连接内的一个轻量级连接。它是执行大多数操作(如消息发布或消息接收)的路径。
- 作用:通道是多路复用连接中的一个独立路径,允许多个通道共享一个 TCP 连接,而不必为每个通道建立物理连接。这提高了资源利用率和通信效率
- 生产者使用通道来发送消息到交换机,而消费者使用通道从队列中接收消息。通道作为消息传输的通道,连接了生产者、交换机和消费者。
通道是作为消息传递的载体贯穿整个过程。
RabbitMQ 的工作流程
工作流程

- 建立连接
- 生产者
- 声明交换机类型、名称、是否持久化等
- 发送消息
- 交换机
- 交换机接收消息,进行消息路由
- 消费者
- 订阅消息(监听队列)
- 接收消息,业务处理
一、消息生产
- 创建连接
- 生产者通过客户端库与RabbitMQ服务器(Broker)建立连接(Connection),并在连接上创建一个信道(Channel)。
- 创建消息(声明交换机,指定 routing key)
- 生产者(Producer)是消息的发送方,它创建包含数据的消息,并指定一个
routing key来描述这条消息的路由规则。
- 生产者(Producer)是消息的发送方,它创建包含数据的消息,并指定一个
- 发送消息
- 生产者将消息发送到一个指定的交换机(Exchange),并附上
routing key。交换机类型和routing key共同决定了消息的路由方式。
- 生产者将消息发送到一个指定的交换机(Exchange),并附上
二、消息路由
- 交换机接收消息
- 交换机根据自身类型(如Direct, Fanout, Topic, Headers)和生产者指定的
routing key来决定如何处理接收到的消息。
- 交换机根据自身类型(如Direct, Fanout, Topic, Headers)和生产者指定的
- 路由队列
- 交换机根据与其绑定的队列(Queue)的
binding key来决定消息应该被路由到哪些队列。 - 对于Direct和Topic交换机,这一过程涉及到
routing key与binding key的匹配。
- 交换机根据与其绑定的队列(Queue)的
三、消息存储
- 消息入队
- 一旦决定了消息的目标队列,消息将被存储在队列中等待被消费。队列保证了消息的有序性和冗余存储。
- 持久化(可选)
- 如果队列被声明为持久化的,并且消息也被标记为持久化,那么消息会被写入磁盘,以确保即使在RabbitMQ重启后消息也不会丢失。
四、消息消费
- 消费者订阅队列
- 消费者(Consumer)通过客户端库与RabbitMQ建立连接,并创建信道。然后它订阅一个或多个队列,准备接收消息。
- 消息发送给消费者
- RabbitMQ将队列中的消息按顺序传递给订阅该队列的消费者。
- 如果有多个消费者订阅同一个队列,RabbitMQ可以按照轮询或其他策略分配消息,以实现负载均衡。
- 消息确认
- 消费者处理完消息后,需要向RabbitMQ发送一个确认(ACK)信号,表示消息已经被正确处理。
- 如果消费者因为某些原因无法处理消息,它可以发送拒绝(NACK)信号或不确认(Reject),让RabbitMQ根据配置进行消息重试或将消息发送到死信队列。
五、消息确认与重试
- 手动与自动确认
- 消费者可以选择手动确认消息或配置自动确认。手动确认给予消费者更大的控制权,但需要在消费者代码中显式处理。
- 失败重试和死信处理
- 对于处理失败的消息,消费者可以通过NACK或Reject并设置重入队列标志来实现重试。或者通过死信交换机(DLX)机制将无法处理的消息转发到死信队列。
交换机类型
(交换机 → 队列)
- Direct Exchange
binding key与消息的routing key完全匹配队列
- Topic Exchange
- 模式匹配
- Fanout Exchange
- 广播(忽略
routing key)
- 广播(忽略
- Headers Exchange
- 不依赖
routing key,头部属性匹配
- 不依赖
RabbitMQ 中最常用的几种交换机类型及其区别:
- Direct Exchange(直接交换机)
- 行为:消息被路由到那些
binding key与消息的routing key完全匹配的队列。 - 用途:非常适合单播(unicast)或多播(multicast)路由场景,即一对一或一对多发送。
- Fanout Exchange(扇出交换机)
- 行为:消息被路由到所有与该交换机绑定的队列,忽略
routing key。 - 用途:非常适合广播消息,如日志系统,其中消息需要被发送到多个目的地。
- Topic Exchange(主题交换机)
- 行为:可以根据模式匹配
routing keys和binding keys(模式中可以包含通配符)。routing key为点分隔的一系列单词,binding key中可以包含特殊字符*和#来进行模式匹配,其中*匹配一个单词,#匹配零个或多个单词。 - 用途:适用于同时需要单播和多播路由逻辑的复杂路由配置。
- Headers Exchange(头部交换机)
- 行为:基于消息头部(headers)中的属性进行匹配。不依赖
routing key。匹配规则可以是“所有”(x-match=all,即所有头部属性必须匹配)或“任何”(x-match=any,即任意头部属性匹配)。 - 用途:适用于需要根据多个属性进行路由决策的高级路由策略。
总结
选择哪种交换机类型主要取决于你的具体应用场景和消息路由需求。
直接交换机适合简单的单播路由,扇出交换机适合广播,主题交换机适合复杂的路由场景,而头部交换机适合基于多属性的路由决策。了解这些交换机的特点可以帮助你更好地设计消息路由策略,并充分利用 RabbitMQ 的强大功能。
RabbitMQ 的处理流程是围绕着连接、交换机、消息发送和消息接收这几个核心环节展开的。
路由键(Routing Key)的作用
路由键是消息发布到 RabbitMQ 时附带的一个字符串标识,它的作用是帮助交换机决定如何路由消息。
这里的“路由”指的是决定消息应该被发送到哪一个或哪些队列。路由键的具体作用取决于交换机的类型:
- Direct Exchange:交换机会将消息路由到那些
binding key与routing key完全匹配的队列。 - Topic Exchange:可以进行模式匹配,交换机会根据
routing key和队列的binding key(可以包含通配符)进行匹配。 - Fanout Exchange:忽略路由键,消息会被发送到所有绑定到该交换机的队列。
- Headers Exchange:不依赖路由键,而是根据发送的消息头部中的键值对进行匹配。
routing key 和 binding key 的作用
routing key- 1、生产者发送消息的时候附加的一个字符串标识符
- 2、这个标识符的作用是:描述消息的路由规则,决定了这个消息应该路由到哪个队列
binding key- 1、队列绑定交换机的时候声明的一个字符串标识符
- 2、这个标识符的作用取决于交换机的类型和预期的消息路由逻辑
单独抽离 消息队列_RabbitMQ_交换机类型#1、RabbitMQ广播和直接模式示例 中关于 Direct Exchange 直接交换机的使用内容:
直接交换机是一种将消息路由到那些binding key与消息的routing key完全匹配的队列的交换机。
RabbitConfig 配置类内容
声明 Direct 交换机
/**
* 声明Direct交换机 支持持久化.
* 通过directExchange方法创建一个名为DIRECT_EXCHANGE的Direct交换机,并设置为支持持久化,这意味着交换机会在RabbitMQ重启后依然存在。
*
* @return the exchange
*/
@Bean("directExchange")
public Exchange directExchange() {
return ExchangeBuilder.directExchange("DIRECT_EXCHANGE").durable(true).build();
}声明一个队列
/**
* 声明一个队列 支持持久化.
*directQueue方法声明了一个名为DIRECT_QUEUE的队列,并设置为持久化。
* @return the queue
*/
@Bean("directQueue")
public Queue directQueue() {
return QueueBuilder.durable("DIRECT_QUEUE").build();
}绑定队列到交换机
/**
* 通过绑定键 将指定队列绑定到一个指定的交换机 .
*directBinding方法通过BindingBuilder将DIRECT_QUEUE队列绑定到DIRECT_EXCHANGE交换机,绑定键为DIRECT_ROUTING_KEY。
* 这意味着只有当消息的routing key为DIRECT_ROUTING_KEY时,消息才会被路由到DIRECT_QUEUE队列。
* @param queue the queue
* @param exchange the exchange
* @return the binding
*/
@Bean
public Binding directBinding(@Qualifier("directQueue") Queue queue,
@Qualifier("directExchange") Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("DIRECT_ROUTING_KEY").noargs();
}发送测试
/**
* 测试Direct模式.
*
* @param p the p
* @return the response entity
*/
public void direct(String p) {
CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
rabbitTemplate.convertAndSend("DIRECT_EXCHANGE", "DIRECT_ROUTING_KEY", p, correlationData);
}交换机与消费者之间的协同
交换机不直接与消费者通信来决定向哪个消费者发送消息。
相反,它依赖于队列和队列与消费者之间的关系来实现消息的分发。下面是它们是如何协同工作的:
- 队列绑定到交换机:队列通过
binding key(在 fanout 和 headers 交换机中,这个binding key不一定被使用)绑定到交换机。这个过程决定了哪些消息会被路由到特定的队列。 - 消费者监听队列:消费者通过打开一个通道并订阅(或监听)一个或多个队列来接收消息。这意味着消费者告诉 RabbitMQ:“我对这个队列中的消息感兴趣,请将它们发送给我。”
- 消息分发:当消息通过交换机被路由到队列后,RabbitMQ 会将队列中的消息发送给订阅该队列的消费者。这个分发过程可能是基于不同的策略,如轮询或公平调度等。
消费者的监听
当我们说消费者“监听”一个队列时,实际上是指消费者开启了一个持续的、异步的过程,这个过程会等待、接收并处理来自队列的消息。
消费者通过通道向 RabbitMQ 注册其对特定队列的兴趣。一旦队列中有消息,RabbitMQ 就会将消息推送给消费者。消费者接收到消息后,会根据自己的逻辑进行处理。
消费者通过监听队列来接收消息,交换机本身并不决定消息发送给哪个消费者,这是由队列中的消息与消费者之间的关系决定的。消费者监听意味着它们准备好接收和处理从队列中来的消息。
二、常见面试题
常见生产问题以及如何处理和常见面试题
- 如何消息不丢失
- 如何避免消息重复消费
- 如何处理消息堆积问题
- 讲述一下 RabbitMQ 的死信队列
- 讲述一下 RabbitMQ 的延迟队列
三、高可用机制
在生产环境下,使用集群来保证高可用性
分为:普通集群、镜像集群、仲裁集群
普通集群
生产环境一般不使用普通集群
普通集群,或者叫标准集群(classic cluster ),具备下列特征:
- 会在集群的各个节点间共享部分数据,包括:交换机、队列元信息。不包含队列中的消息。
- 当访问集群某节点时,如果队列不在该节点,会从数据所在节点传递到当前节点并返回
- 队列所在节点宕机,队列中的消息就会丢失
镜像集群
镜像集群:本质是主从模式,具备下面的特征:
- 交换机、队列、队列中的消息会在各个 mq 的镜像节点之间同步备份。
- 创建队列的节点被称为该队列的主节点,备份到的其它节点叫做该队列的镜像节点。
- 一个队列的主节点可能是另一个队列的镜像节点
- 所有操作都是主节点完成,然后同步给镜像节点
- 主宕机后,镜像节点会替代成新的主节点
仲裁队列
仲裁队列:仲裁队列是3.8版本以后才有的新功能,用来替代镜像队列,具备下列特征:
- 与镜像队列一样,都是主从模式,支持主从数据同步
- 使用非常简单,没有复杂的配置
- 主从同步基于Raft协议,强一致 ·
面试题回答:RabbitMQ 的高可用机制有了解过吗

参考回答;

参考